package com.github.chain.admin.server.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.chain.admin.common.constants.AdminConst;
import com.github.chain.admin.common.domain.*;
import com.github.chain.admin.common.enums.AdminErrorMsgEnum;
import com.github.chain.admin.common.enums.MenuTypeEnum;
import com.github.chain.admin.common.request.MenuRequest;
import com.github.chain.admin.server.dao.*;
import com.github.chain.admin.server.service.MenuService;
import com.github.framework.core.Result;
import com.github.framework.core.exception.Ex;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author AIQ
 * @date 2023/5/11
 * @project er-trader
 */
@Service
@Slf4j
public class MenuServiceImpl implements MenuService {

    @Resource
    private UserDao userDao;

    @Resource
    private RoleDao roleDao;

    @Resource
    private MenuDao menuDao;

    @Resource
    private UserRoleDao userRoleDao;

    @Resource
    private RoleMenuDao roleMenuDao;

    @Override
    public Result<TreeMap<Long, Menu>> findMenuByUserId(Long userId) {

        if (userId == null){
            log.error("查询用户对应菜单请求参数为空");
            return Result.fail(AdminErrorMsgEnum.REQUEST_PARAMS_IS_EMPTY);
        }

        User user = userDao.findUserByUserId(userId);
        if (user == null || !user.getStatus().equals(AdminConst.START_STATUS)){
            log.error("当前用户:{}不存在", userId);
            return Result.fail(AdminErrorMsgEnum.CURRENT_USER_NOT_EXIST);
        }

        List<UserRole> userRoleList = userRoleDao.findUserRoleByUserId(userId);
        if (CollectionUtils.isEmpty(userRoleList)){
            log.error("当前根据用户id查询对应的用户角色信息不存在, userId:{}, userName:{}", user.getId(), user.getUserName());
            return Result.fail(AdminErrorMsgEnum.CURRENT_USER_ROLE_NOT_EXIST);
        }

        List<Long> roleIdsList = new ArrayList<>();
        userRoleList.stream().forEach(u -> {
            roleIdsList.add(u.getRoleId());
        });

        List<Role> roleList = roleDao.findRoleByRoleIds(roleIdsList);
        List<Long> roleIdItemsList = new ArrayList<>();

        if (CollectionUtils.isEmpty(roleList)){
            log.error("根据提示角色id集合查询对应角色不存在：userId:{}, userName:{}, roleIdsList:{}", user.getId(), user.getUserName(), roleIdsList);
            return Result.fail(AdminErrorMsgEnum.CURRENT_ROLE_NOT_EXIST);
        }

        roleList.stream().filter(u -> u.getStatus().equals(AdminConst.START_STATUS)).forEach(role -> roleIdItemsList.add(role.getId()));

        log.info("查询成功用户角色数据, userId:{}, 角色id:{}", userId, roleIdItemsList);

        List<RoleMenu> roleMenuList = roleMenuDao.findRoleMenuByRoleIds(roleIdItemsList);
        List<Long> menuIdsList = new ArrayList<>();

        if (CollectionUtils.isEmpty(roleMenuList)){
            log.error("当前userId:{}, roleIds:{} 查询对应角色菜单不存在", userId, roleIdItemsList);

            return Result.fail(AdminErrorMsgEnum.CURRENT_ROLE_MENU_NOT_EXIST);
        }

        for (RoleMenu menu : roleMenuList){
            menuIdsList.add(menu.getMenuId());
        }

        List<Menu> menuList = menuDao.findMenuByMenuIds(menuIdsList);

        Map<Long, Menu> keyMenu = new HashMap<>();

        TreeMap<Long, Menu> treeMenu = new TreeMap<>();

        if (CollectionUtils.isEmpty(menuList)){
            log.error("当前根据角色菜单查询对应的菜单不存在, userId:{}, menuIdsList:{}", userId, menuIdsList);

            return Result.fail(AdminErrorMsgEnum.CURRENT_MENU_NOT_EXIST);
        }

        // 过滤以启用的菜单，菜单有3中状态，以启用的菜单是1，冻结的是2，删除的是3
        menuList.stream().filter(m -> m.getStatus().equals(AdminConst.START_STATUS)).forEach(m -> keyMenu.put(m.getId(), m));

        keyMenu.forEach((id, menu) -> {
            if (menu.getType() != MenuTypeEnum.BUTTON.getCode()){
                if (keyMenu.get(menu.getPid()) != null){
                    keyMenu.get(menu.getPid()).getChildren().put(Long.valueOf(menu.getSort()), menu);
                } else {
                    if (menu.getType() == MenuTypeEnum.DIRECTORY.getCode()){
                        treeMenu.put(Long.valueOf(menu.getSort()), menu);
                    }
                }
            }
        });


        if (MapUtils.isEmpty(treeMenu)){

            log.error("当前map集合菜单数据不存在，userId:{}, menuIdsList:{}", userId, menuIdsList);
            return Result.fail(AdminErrorMsgEnum.CURRENT_MENU_NOT_EXIST);
        }

        log.info("查询用户userID:{}, 对应的菜单集合treeMap:{}", userId, treeMenu);

        return Result.ok(treeMenu);
    }

    @Override
    public Result<List<Menu>> roleMenuAuthList(Long id) {

        if (id == null){
            log.error("角色菜单授权请求角色id为空");
            return Result.fail(AdminErrorMsgEnum.REQUEST_PARAMS_IS_EMPTY);
        }

        Role role = roleDao.findRoleById(id);

        if (role == null){
            log.error("当前菜单授权角色id:{}对应角色不存在", id);
            return Result.fail(AdminErrorMsgEnum.CURRENT_ROLE_NOT_EXIST);
        }

        List<RoleMenu> roleMenuList = roleMenuDao.findRoleMenuByRoleId(id);
        if (CollectionUtils.isEmpty(roleMenuList)){
            log.error("角色菜单数据不存在, roleId:{}", id);
            return Result.ok(menuDao.findMenuByMenuIds(null));
        }

        List<Long> menuIdsList = new ArrayList<>();

        roleMenuList.stream().forEach(roleMenu -> {
            menuIdsList.add(roleMenu.getMenuId());
        });

        log.info("角色菜单对饮的菜单id集合数据，menuIdsList:{}", menuIdsList);

        List<Menu> menuList = menuDao.findMenuByMenuIds(menuIdsList);
        if (CollectionUtils.isEmpty(menuList)){
            log.error("角色roleId:{}, 角色菜单集合menuIdsList:{}查询对应的菜单数据为空", id, menuIdsList);
            return Result.fail(AdminErrorMsgEnum.CURRENT_MENU_NOT_EXIST);
        }

        Set<Menu> menuSet = menuList.stream().collect(Collectors.toSet());

        List<Menu> allMenuList = menuDao.findMenuByMenuIds(null);

        for (Menu menu : allMenuList) {

            String remark = "-";
            if (menuSet.contains(menu)){
                remark = "auth:true";
                menu.setRemark(remark);
            }
        }

        role.setMenuList(allMenuList);
        log.info("查询角色对应的菜单JSON数据:{}", JSON.toJSONString(role));

        return Result.ok(allMenuList);
    }

    @Override
    public Result<List<Menu>> findMenuList(MenuRequest menuRequest) {
        Menu menu = new Menu();
        BeanUtils.copyProperties(menuRequest, menu);
        List<Menu> list = menuDao.findMenuList(menu);
        list.stream().forEach(menu1 -> {
            Integer type = menu1.getType();
            if (type == 1){
                menu1.setRemark("目录");
            } else if (type == 2){
                menu1.setRemark("菜单");
            } else if (type == 3){
                menu1.setRemark("按钮");
            }  else {
                menu1.setRemark("-");
            }
            menu1.setChildren(null);
        });

        log.info("哈哈哈哈哈哈哈哈：{}", list);
        return Result.ok(list);
    }

    @Override
    public Result<Map<Integer, String>> findMenuListSort(MenuRequest menuRequest) {

        Long pid = menuRequest.getPid();
        if (pid == null){
            log.error("菜单父id请求参数为空");
            return Result.fail(AdminErrorMsgEnum.REQUEST_PARAMS_IS_EMPTY);
        }

        Long id = menuRequest.getId();
        if (id == null){
            id = 0L;
        }

        List<Menu> menuList = menuDao.findMenuListSortByPid(pid);

        Map<Integer, String> map = new HashMap<>();

        for (Menu menu : menuList) {
            if (!menu.getId().equals(id)){
                map.put(menu.getSort(), menu.getTitle());
            }

        }
        return Result.ok(map);
    }

    @Override
    public Result<Menu> findMenuById(Long id) {

        if (id == null){

            log.error("当前id为空");
            return Result.fail(AdminErrorMsgEnum.REQUEST_PARAMS_IS_EMPTY);
        }

        Menu menu = menuDao.findMenuById(id);

        if (menu == null){
            log.error("未找到此菜单，请重试");
            return Result.fail(AdminErrorMsgEnum.CURRENT_MENU_NOT_EXIST);
        }

        Menu menuById = menuDao.findMenuById(menu.getPid());

        log.info("当前菜单为menu:{}", menuById);
        return Result.ok(menuById);
    }

    @Override
    public Result<Integer> saveMenu(MenuRequest menuRequest) {

        if (menuRequest == null){
            log.error("保存菜单请求对象或者pid为空");
            return Result.fail(AdminErrorMsgEnum.REQUEST_PARAMS_IS_EMPTY);
        }

        Long pid = menuRequest.getPid();
        Menu menu = new Menu();
        Date date = new Date();
        BeanUtils.copyProperties(menuRequest, menu);
        menu.setCreateDate(date);

        Integer menuType = menuRequest.getType();
        if (menuType == null){
            log.error("pid: {} 菜单类型为空", pid);
            return Result.fail(AdminErrorMsgEnum.MENU_TYPE_IS_EMPTY);
        }
        Menu pidMenu;
        if (pid == 0){
            menu.setPids("[" + pid + "]");
            if (menuType != 1){
                log.error("保存菜单pid: {}请选择正确的菜单类型menuType: {}", pid, menuType);
                return Result.fail(AdminErrorMsgEnum.SELECT_THE_CORRECT_MENU_TYPE);
            }
        } else {

            pidMenu = menuDao.findMenuById(pid);
            if (pidMenu == null){
                log.error("保存菜单pid: {}对应父级菜单不存在", pid);
                return Result.fail(AdminErrorMsgEnum.CURRENT_MENU_NOT_EXIST);
            }

            Integer pidMenuType = pidMenu.getType();
            if ((menuType - 1) != pidMenuType){
                log.error("保存菜单类型选择类型不正确, pidMenuType: {}, menuType: {}", pidMenuType, menuType);
                return Result.fail(AdminErrorMsgEnum.CURRENT_MENU_NOT_EXIST);
            }
            menu.setPids(pidMenu.getPids() + ",[" + pid + "]");
        }

        Integer menuSort = menuRequest.getSort();
        if (menuSort == null){
            log.error("保存菜单排序为空, pid: {}", pid);
            return Result.fail(AdminErrorMsgEnum.MENU_SORT_IS_EMPTY);
        }

        menuSort++;
        List<Menu> sortMenuList = menuDao.findMenuListSortByPid(pid);
        if (CollectionUtils.isNotEmpty(sortMenuList)){

            for (Menu m : sortMenuList){
                if (m.getSort() >= menuSort){
                    Menu updateMenu = new Menu();
                    updateMenu.setId(m.getId());
                    updateMenu.setSort(m.getSort() + 1);

                    Integer updateStatus = menuDao.updateSelective(updateMenu);
                    if (updateStatus != 1){
                        throw Ex.business(AdminErrorMsgEnum.DATABASE_OPTION_EXCEPTION);
                    }
                }
            }
        }

        menu.setSort(menuSort);

        Integer status = menuDao.insertSelective(menu);
        if (status != 1) {
            throw Ex.business(AdminErrorMsgEnum.DATABASE_OPTION_EXCEPTION);
        }

        return Result.ok(status);
    }

    @Override
    public Result<Menu> findMenuByMenuId(Long id) {

        if (id == null){
            log.error("当前菜单id不存在001");
            return Result.fail(AdminErrorMsgEnum.CURRENT_MENU_NOT_EXIST);
        }

        Menu menu = menuDao.findMenuById(id);
        if (menu == null){
            log.error("当前菜单不存在002");
            return Result.fail(AdminErrorMsgEnum.CURRENT_MENU_NOT_EXIST);
        }

        User createBy = userDao.findUserByUserId(menu.getCreateBy());
        User updateBy = userDao.findUserByUserId(menu.getUpdateBy());
        if (createBy == null && updateBy == null){
            log.error("未找到当前用户");
            return Result.fail(AdminErrorMsgEnum.CURRENT_USER_NOT_EXIST);
        }

        menu.setCreateUser(createBy);
        menu.setUpdateUser(updateBy);

        return Result.ok(menu);
    }

    @Override
    @Transactional
    public Result<Integer> updateMenu(MenuRequest menuRequest) {

        if (menuRequest == null || menuRequest.getId() == null){
            log.error("修改菜单请求数据menuRequest为空");
            return Result.fail(AdminErrorMsgEnum.REQUEST_PARAMS_IS_EMPTY);
        }
        Long id = menuRequest.getId();
        Integer menuType = menuRequest.getType();

        Menu menuMy = menuDao.findMenuById(id);

        if (menuRequest.getPid().equals(menuMy.getId())){
            log.error("请选择正确的菜单类型");
            return Result.fail(AdminErrorMsgEnum.SELECT_THE_CORRECT_MENU_TYPE);
        }

        //查询自己的菜单下是否有子菜单
        if (menuRequest.getPid() != 0) {
            List<Menu> sonMenuList = menuDao.findMenuListSortByPid(id);
            if (CollectionUtils.isNotEmpty(sonMenuList) || sonMenuList.size() > 0) {
                log.error("该目录下已有数据不能进行更换类型id:{}，type:{}，若想更改则修改其子类类型", id, menuType);
                return Result.fail(AdminErrorMsgEnum.MENU_EXIST_SUBMENU);
            }
        }

        Menu menu = new Menu();
        BeanUtils.copyProperties(menuRequest,menu);
        menu.setUpdateDate(new Date());

        Long pid = menu.getPid();
        if (pid == 0){
            menu.setPids("[" + pid + "]");
            if (menuType != 1){
                log.error("修改菜单menuType:{},pid:{},菜单类型选择不正确",menuType,pid);
                return Result.fail(AdminErrorMsgEnum.SELECT_THE_CORRECT_MENU_TYPE);
            }
        }else {
            Menu pidMenu = menuDao.findMenuById(pid);
            if (pidMenu == null){
                log.error("修改菜单根据pid:{}查询对应的父级菜单不存在",pid);
                return Result.fail(AdminErrorMsgEnum.CURRENT_MENU_NOT_EXIST);
            }

            if ((menuType -1) != pidMenu.getType()){
                log.error("修改菜单菜单类型选择不正确menuType:{}",menuType);
                return Result.fail(AdminErrorMsgEnum.SELECT_THE_CORRECT_MENU_TYPE);
            }
            menu.setPids(pidMenu.getPids() + ",[" + pid + "]");
        }

        Integer sort = menu.getSort();
        if (sort == null){
            log.error("修改菜单排序为空,pid:{}",pid);
            return Result.fail(AdminErrorMsgEnum.MENU_SORT_IS_EMPTY);
        }

        sort++;
        //查出所选父级菜单下的所有子菜单
        List<Menu> sortMenuList = menuDao.findMenuListSortByPid(pid);
        Integer status = 0;
        int menuSort = sort + 1;
        for (Menu sortMenu : sortMenuList) {
            Menu sMenu = new Menu();
            if (sortMenu.getSort() >= sort) {
                if (!sortMenu.getId().equals(id)) {
                    sMenu.setId(sortMenu.getId());
                    sMenu.setSort(menuSort++);
                    status = menuDao.updateSelective(sMenu);
                    if (status != 1) {
                        return Result.fail(AdminErrorMsgEnum.DATABASE_OPTION_EXCEPTION);
                    }
                }
            }
        }

        menu.setSort(sort);
        status = menuDao.updateSelective(menu);
        if (status != 1){
            return Result.fail(AdminErrorMsgEnum.DATABASE_OPTION_EXCEPTION);
        }
        return Result.ok(status);
    }

    @Override
    public Result<Integer> deleteMenuByMenuId(Long id) {

        if (id == null || id < 0){
            log.error("菜单id参数错误");
            return Result.fail(AdminErrorMsgEnum.REQUEST_PARAMS_IS_EMPTY);
        }

        Integer count = menuDao.deleteMenuByMenuId(id);

        if (count == null){
            log.error("未找到该菜单");
            return Result.fail(AdminErrorMsgEnum.MENU_TYPE_IS_EMPTY);
        }

        return Result.ok(count);
    }
}
